using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using UnityEngine;

public class NetConnUDP
{
    private string ip;
    private uint port = 12345;

    private bool isStarted = false;

    private UdpClient client = null;
    private Task<UdpReceiveResult> readTask = null;

    public interface IReader
    {
        bool OnRead(byte[] buffer);
    }

    public IReader reader;

    public delegate void OnError();

    public event OnError onError;

    public NetConnUDP()
    {
        
    }

    public void SetAddress(string ip,uint port)
    {
        this.ip = ip;
        this.port = port;
    }

    public bool Start()
    {
        bool ok = false;

        do
        {
            if(isStarted)
            {
                break;
            }

            try
            {
                client = new UdpClient();

                client.Connect(ip,(int)port);

                isStarted = true;

                readTask = client.ReceiveAsync();

                ok = true;
            }
            catch(Exception ex)
            {
                Debug.LogError("NetConnUDP Start Exception:" + ex);
            }

        }while(false);

        if(!ok)
        {
            _Stop();
        }

        return ok;
    }

    private void _Stop()
    {
        try
        {
            if(client != null)
            {
                client.Close();
            }
        }
        catch(Exception ex)
        {
            Debug.LogError("NetConnUDP _Stop client Exception:" + ex);
        }               

        isStarted = false;
        readTask = null;
        client = null;
    }

    public void Stop()
    {
        if(!isStarted)
        {
            return;
        }

        _Stop();
    }

    public void Update()
    {
        if(!isStarted)
        {
            return;
        }

        if(readTask != null && readTask.IsCompleted)
        {
            Task<UdpReceiveResult> task = readTask;
            readTask = null;

            if(task.Status != TaskStatus.RanToCompletion)
            {
                Debug.Log("NetConnUDP ReadError! task status:" 
                    + task.Status + 
                    (task.Exception != null ? 
                        (" Exception:" + task.Exception.ToString()) : "")
                );

                _Stop();

                if(onError != null)
                {
                    onError();
                }
                return;
            }

            try
            {
                if(reader != null)
                {
                    if(!reader.OnRead(task.Result.Buffer))
                    {
                        Debug.Log("NetConnUDP OnRead failed!"); 

                        _Stop();

                        if(onError != null)
                        {
                            onError();
                        }
                        return;
                    }
                }
            }
            catch(Exception ex)
            {
                Debug.Log("NetConnUDP callback Exception:" + ex.ToString());
            }

            try
            {
                if(client != null)
                {
                    readTask = client.ReceiveAsync();
                }
            }
            catch(Exception ex)
            {
                 Debug.Log("NetConnUDP post recv Exception:" + ex.ToString());

                _Stop();

                if(onError != null)
                {
                    onError();
                }
            }
        }
    }

    public bool SendMessage(byte[] buffer,int count)
    {
        bool ok = false;

        do
        {
            if(!isStarted)
            {
                break;
            }

            try
            {
                client.Send(buffer,count);

                ok = true;

                Debug.Log("NetConnUDP SendMessage count:" + count);
            }
            catch(Exception ex)
            {
                Debug.LogError("NetConnUDP SendMessage Exception:" + ex + " msg count:" + count);
            }

        }while(false);

        return ok;
    }
}   